﻿#--------------------------------------------------------------------------------------------------------------------------------------------------------
#
# Mi-DevEnv			:	http://midevenv.codeplex.com 
#					:	(c) IT Bridge 2012
#					:	A concept originated by Chris Nurse
#
# Licence			:	GNU General Public License version 2 (GPLv2)
#					:	http://midevenv.codeplex.com/license
#
# Summary           :   This script provides management of the virtualisation platform
#
#--------------------------------------------------------------------------------------------------------------------------------------------------------

Set-StrictMode -Version Latest

if ((Get-Module MDE-Common) -eq $null) {
    Import-Module MDE-Common
    }

[string]$executionPath = Split-Path $script:MyInvocation.MyCommand.Path -Parent
[string]$VirtualPlatform = $null

if ((Get-WindowsFeature "Hyper-V" -ErrorAction SilentlyContinue) -ne $null) {
	Import-Module "$executionPath\MDE-VM-HyperV.psm1" -Force
    $VirtualPlatform = "HYPERV"
	}
else {
    throw "Can't detect a supported virtual platform"
    }

Function New-Machine() {
Param(
[Parameter(mandatory=$true)] [Alias("MNM")][string]$MachineName,
[Parameter(mandatory=$false)][Alias("RAM")][int]$MemoryMB=$DefaultVirtualMemoryMB, 
[Parameter(mandatory=$false)][Alias("VNT")][string]$Network=$DefaultVirtualNetwork, 
[Parameter(mandatory=$true)] [Alias("DRV")][string]$DriveTemplate,
[Parameter(mandatory=$false)][Alias("DIF")][switch]$Differencing=$true,
[Parameter(mandatory=$false)][Alias("DLT")][switch]$DeleteIfExists=$false,
[Parameter(mandatory=$false)][Alias("PKG")][string]$Packages=$null,
[Parameter(mandatory=$false)][Alias("FTR")][string]$Features=$null,
[Parameter(mandatory=$false)][Alias("RGC")][string]$RegisteredCompany=$DefaultRegisteredCompany, 
[Parameter(mandatory=$false)][Alias("RGU")][string]$RegisteredUser=$DefaultRegisteredUser,
[Parameter(mandatory=$false)][Alias("ADM")][string]$AdminUser=$DefaultAdminUser,
[Parameter(mandatory=$false)][Alias("APS")][string]$AdminPassword=$DefaultPassword, 
[Parameter(mandatory=$false)][Alias("PID")][string]$ProductKey=$null, 
[Parameter(mandatory=$false)][Alias("WUP")][int]$WindowsUpdate=$DefaultWindowsUpdate
) 

Write-Header "Deploy Virtual Machine"

#region Verbose Header

    $validationMessage = "Passed"

    if (Test-Connection $MachineName -Quiet -Count 1) {
        $Error = $true
        $validationMessage = "Computer named $MachineName exists on network"
        }

    Write-Verbose "Processing request to create new virtual machine"
    Write-Verbose "------------------------------------------------"
    Write-Verbose "MachineName        $MachineName" 
    Write-Verbose "Memory             $MemoryMB MB" 
    Write-Verbose "Network            $Network" 
    Write-Verbose "DriveTemplate      $DriveTemplate, Use differencing=$Differencing" 
    Write-Verbose "DeleteIfExists     $DeleteIfExists" 
    Write-Verbose "Packages           $Packages" 
    Write-Verbose "Features           $Features" 
    Write-Verbose "RegisteredCompany  $RegisteredCompany" 
    Write-Verbose "RegisteredUser     $RegisteredUser" 
    Write-Verbose "AdminUser          $AdminUser" 
    Write-Verbose "AdminPassword      $AdminPassword" 

    if ([string]::IsNullOrEmpty($ProductKey)) {
        $ProductKey = Get-Setting($DriveTemplate)
        Write-Verbose "ProductKey         $ProductKey (Default for $DriveTemplate)" 
        }
    else {
        Write-Verbose "ProductKey         $ProductKey" 
        }

    Write-Verbose "WindowsUpdate      $WindowsUpdate"
    Write-Verbose "Validation         $ValidationMessage" 
    Write-Verbose ""

    if ($Error) {
        Write-Host "Virtual machine deployment terminated by error" -ForegroundColor Red
        break
        }

#endregion

    if ($DeleteIfExists) {
        Write-Verbose "Delete virtual machine $MachineName if it exists"
        Remove-VirtualMachine -MachineName $MachineName -Confirm:$false
        Write-Verbose "Delete virtual drive for $MachineName if it exists"
        Remove-VirtualDrive -MachineName $MachineName -Confirm:$false
        }
    elseif ((Get-MachineExists -MachineName $MachineName) -eq $true) {
        throw "Can not create new virtual machine $MachineName, a virtual machine of this name already exists but may be switched off"
        }

    Write-Verbose "Create virtual drive use $MachineName as disk name"
    New-VirtualDrive -MachineName $MachineName -TemplateName $DriveTemplate -Differencing:$Differencing

    # Mount VHD as a local drive so items can be copied to the drive which will drive the new virtual machine's boot process
    Write-Verbose "Mounting virtual drive"
    [string]$VirtualDrive = Mount-VirtualDrive -MachineName $MachineName

    $root = "$VirtualDrive" + ":\"

    if (!(Test-Path ($root))) {
        # If direct access to the virtual disk fails, use a PowerShell drive
        $VirtualDrive = Get-FreeDriveLetter
        New-PSDrive -Scope Global -Name $VirtualDrive -Root $root -PSProvider FileSystem -Description "MiDevEnv ScriptInstaller" | Out-Null
        Write-Verbose "Using PowerShell drive to access virtual drive"
        }

    Write-Verbose "Virtual drive mounted as $VirtualDrive"

    # Assume a sysprep response file exists which is the same name as the drive template
    $SysPrepFile= "$LocalRootFolder\MDE-Initialisation\SysPrepResponse\$DriveTemplate.xml"
    Write-Verbose "Template sysprep response file $SysPrepFile"

	Install-Scripts -Verbose:$VerbosePreference -Drive $VirtualDrive -Packages $Packages -Features $Features -SysPrepResponse $SysPrepFile
    
    Remove-DriveMappings -DescriptionKey "MiDevEnv ScriptInstaller"

    Write-Verbose "Unmount virtual drive"
    Dismount-VirtualDrive -MachineName $MachineName
    Write-Verbose ""

    Write-Verbose "Create new virtual machine $MachineName with $MemoryMB MB of RAM and assign network $Network"
    New-VirtualMachine -Verbose:$VerbosePreference -MachineName $MachineName -MemoryMB $MemoryMB -VirtualNetwork $Network

    Write-Verbose "Starting $MachineName"
    Start-VirtualMachine -Verbose:$VerbosePreference -MachineName $MachineName
    Write-Verbose ""
    Write-Verbose "Process complete"
    }

Function Remove-Machine() {
Param(
[Parameter(mandatory=$true)] [Alias("MNM")][string]$MachineName,
[Parameter(mandatory=$false)][switch]$Confirm=$false
)
    Write-Verbose "Delete virtual machine $MachineName"
    Remove-VirtualMachine -MachineName $MachineName -Confirm:$Confirm
    Remove-VirtualDrive   -MachineName $MachineName -Confirm:$Confirm
    }

Function Install-Scripts() {
Param(
[Parameter(mandatory=$true)][string]$Drive,
[Parameter(mandatory=$false)][string]$Packages=$null,
[Parameter(mandatory=$false)][string]$Features=$null,
[Parameter(mandatory=$true)][string]$SysPrepResponse
)
    $destFolder = "$Drive`:\$VmDeployFolder"
    $tempFolder = $TemporaryFolder + [guid]::NewGuid()
    
    Write-Verbose "Create working folder $tempFolder"
    New-Item -Path $tempFolder -ItemType Directory -ErrorAction Stop | Out-Null
    
    if (Test-Path $destFolder) {
        Write-Verbose "Script files detected on virtual drive, removing folder $destFolder"
        Remove-Item -Recurse -Force -Path $destFolder -ErrorAction Stop
        }

    Write-Verbose "Create target folder $destFolder"
    New-Item -Path $destFolder -ItemType Directory -ErrorAction Stop | Out-Null

    if ([string]::IsNullOrEmpty($SysPrepResponse) -or (Test-Path $SysPrepResponse) -eq $false) {
        throw "SysPrepResponse parameter can not be null or zero length and must be a valid path to a SysPrep reponse file."
        }


    Write-Verbose "Copy non-cutomised scripts from $ScriptSource to $destFolder"
    Get-ChildItem $ScriptSource | Copy-Item -Recurse -Destination $destFolder -Force

    Write-Verbose "Write customised scripts to $destFolder\MDE-Installers"
    Copy-DeploymentScripts -Verbose:$VerbosePreference -Source "$LocalRootFolder\MDE-TemplateScripts" -Destination "$tempFolder"
    Copy-Item -Path $tempFolder -Recurse -Destination "$destFolder\MDE-Installers" -Force

    if (![string]::IsNullOrEmpty($Packages)) {
        $buildFile = "$destFolder\MDE-Installers\BuildPackages.csv"
        Write-Verbose "Writing requested packages ($Packages) to $buildFile"

        $content = ("Package`r`n" + $Packages.Replace(",","`r`n")) 
        Set-Content -Path "$tempFolder\BuildPackages.csv" -Force -Value $content
        Copy-Item -Path "$tempFolder\BuildPackages.csv" -Destination $buildFile -Force
        }

    if (![string]::IsNullOrEmpty($Features)) {
        $buildFile = "$destFolder\MDE-Installers\ServerFeatures.csv"
        Write-Verbose "Writing requested feastures ($Features) to $buildFile"

        $content = ("Feature`r`n" + $Features.Replace(",","`r`n")) 
        Set-Content -Path "$tempFolder\ServerFeatures.csv" -Force -Value $content
        Copy-Item -Path "$tempFolder\ServerFeatures.csv" -Destination $buildFile -Force
        }
        

    Write-Verbose "Read SysPrep response file $SysPrepResponse"
    $content = Get-Content $SysPrepResponse
    $unattendFile = "$destFolder\MDE-Initialisation\Unattend.Xml"
    
    # Set SysPrep values
    $content = $content.Replace("MDE_DOMAIN_NAME", "")
    $content = $content.Replace("MDE_DEFAULT_PASSWORD",$AdminPassword)
    $content = $content.Replace("MDE_MACHINE_NAME",$MachineName)
    $content = $content.Replace("MDE_WINDOWSUPDATE",$WindowsUpdate)
    $content = $content.Replace("MDE_PRODUCT_KEY",$ProductKey)
    $content = $content.Replace("MDE_ORGANISATION_NAME",$RegisteredCompany)
    $content = $content.Replace("MDE_USER",$RegisteredUser)
    $content = $content.Replace("MDE_AUTOLOGIN_ADMIN",$AdminUser)
    $content = $content.Replace("MDE_TIMEZONE",$DefaultTimezone)
    $content = $content.Replace("MDE_LOCALE",$DefaultLocale)
    $content = $content.Replace("MDE_POST_SYSPREP_COMMAND",$PostSysPrepCommand)
    
    Write-Verbose "Create SysPrep response file $unattendFile"
    Set-Content -Path "$tempFolder\Unattend.xml" -Force -Value $content
    Copy-Item -Path "$tempFolder\unattend.xml" -Destination $unattendFile -Force


    Write-Verbose "Remove temporary folder $tempFolder"
    Remove-Item $tempFolder -Recurse -Force -Confirm:$false


    Write-Verbose "Install modules in PowerShell module directory"
    $psModulePath = "$Drive`:\Windows\System32\WindowsPowerShell\v1.0\Modules"
    $modules= @("MDE-Host","MDE-Common")

    foreach($module in $modules) {
        Write-Verbose "Installing $module"

        if (!(Test-Path "$psModulePath\$module")) {
            New-Item -ItemType Directory -Path "$psModulePath\$module" | Out-Null
            }

        Copy-Item "$destFolder\$module\*.*" "$psModulePath\$module" -Force
        }
    }

Export-ModuleMember -Function *
Export-ModuleMember -Variable *